﻿using Pathfinding;
using Pathfinding.Util;
using System;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;

[AddComponentMenu("Pathfinding/Debugger"), ExecuteInEditMode]
public class AstarDebugger : MonoBehaviour
{
    private int allocMem;
    private int allocRate;
    private Rect boxRect;
    private string cachedText;
    private Camera cam;
    private int collectAlloc;
    private PathTypeDebug[] debugTypes = new PathTypeDebug[] { new PathTypeDebug("ABPath", new Func<int>(PathPool<ABPath>.GetSize), new Func<int>(PathPool<ABPath>.GetTotalCreated)) };
    private float delayedDeltaTime = 1f;
    private float delta;
    public Font font;
    public int fontSize = 12;
    private int fpsDropCounterSize = 200;
    private float[] fpsDrops;
    private GraphPoint[] graph;
    public int graphBufferSize = 200;
    private float graphHeight = 100f;
    private float graphOffset = 50f;
    private float graphWidth = 100f;
    private int lastAllocMemory;
    private float lastAllocSet = -9999f;
    private float lastCollect;
    private float lastCollectNum;
    private float lastDeltaTime;
    private float lastUpdate = -999f;
    private LineRenderer lineRend;
    private int maxNodePool;
    private int maxVecPool;
    private int peakAlloc;
    public bool show = true;
    public bool showFPS;
    public bool showGraph;
    public bool showInEditor;
    public bool showMemProfile;
    public bool showPathProfile;
    private GUIStyle style;
    private StringBuilder text = new StringBuilder();
    public int yOffset = 5;

    public void Cross(Vector3 p)
    {
        p = this.cam.cameraToWorldMatrix.MultiplyPoint(p);
        Debug.DrawLine(p - ((Vector3) (Vector3.up * 0.2f)), p + ((Vector3) (Vector3.up * 0.2f)), Color.red);
        Debug.DrawLine(p - ((Vector3) (Vector3.right * 0.2f)), p + ((Vector3) (Vector3.right * 0.2f)), Color.red);
    }

    public void DrawGraphLine(int index, Matrix4x4 m, float x1, float x2, float y1, float y2, Color col)
    {
        Debug.DrawLine(this.cam.ScreenToWorldPoint(m.MultiplyPoint3x4(new Vector3(x1, y1))), this.cam.ScreenToWorldPoint(m.MultiplyPoint3x4(new Vector3(x2, y2))), col);
    }

    public void OnGUI()
    {
        if (this.show && (Application.isPlaying || this.showInEditor))
        {
            if (this.style == null)
            {
                this.style = new GUIStyle();
                this.style.normal.textColor = Color.white;
                this.style.padding = new RectOffset(5, 5, 5, 5);
            }
            if ((((Time.realtimeSinceStartup - this.lastUpdate) > 0.5f) || (this.cachedText == null)) || !Application.isPlaying)
            {
                this.lastUpdate = Time.realtimeSinceStartup;
                this.boxRect = new Rect(5f, (float) this.yOffset, 310f, 40f);
                this.text.Length = 0;
                this.text.AppendLine("A* Pathfinding Project Debugger");
                this.text.Append("A* Version: ").Append(AstarPath.Version.ToString());
                if (this.showMemProfile)
                {
                    this.boxRect.height += 200f;
                    this.text.AppendLine();
                    this.text.AppendLine();
                    this.text.Append("Currently allocated".PadRight(0x19));
                    this.text.Append((((float) this.allocMem) / 1000000f).ToString("0.0 MB"));
                    this.text.AppendLine();
                    this.text.Append("Peak allocated".PadRight(0x19));
                    float num11 = ((float) this.peakAlloc) / 1000000f;
                    this.text.Append(num11.ToString("0.0 MB")).AppendLine();
                    this.text.Append("Last collect peak".PadRight(0x19));
                    float num12 = ((float) this.collectAlloc) / 1000000f;
                    this.text.Append(num12.ToString("0.0 MB")).AppendLine();
                    this.text.Append("Allocation rate".PadRight(0x19));
                    float num13 = ((float) this.allocRate) / 1000000f;
                    this.text.Append(num13.ToString("0.0 MB")).AppendLine();
                    this.text.Append("Collection frequency".PadRight(0x19));
                    this.text.Append(this.delta.ToString("0.00"));
                    this.text.Append("s\n");
                    this.text.Append("Last collect fps".PadRight(0x19));
                    this.text.Append((1f / this.lastDeltaTime).ToString("0.0 fps"));
                    this.text.Append(" (");
                    this.text.Append(this.lastDeltaTime.ToString("0.000 s"));
                    this.text.Append(")");
                }
                if (this.showFPS)
                {
                    this.text.AppendLine();
                    this.text.AppendLine();
                    float num15 = 1f / this.delayedDeltaTime;
                    this.text.Append("FPS".PadRight(0x19)).Append(num15.ToString("0.0 fps"));
                    float positiveInfinity = float.PositiveInfinity;
                    for (int i = 0; i < this.fpsDrops.Length; i++)
                    {
                        if (this.fpsDrops[i] < positiveInfinity)
                        {
                            positiveInfinity = this.fpsDrops[i];
                        }
                    }
                    this.text.AppendLine();
                    this.text.Append(("Lowest fps (last " + this.fpsDrops.Length + ")").PadRight(0x19)).Append(positiveInfinity.ToString("0.0"));
                }
                if (this.showPathProfile)
                {
                    AstarPath active = AstarPath.active;
                    this.text.AppendLine();
                    if (active == null)
                    {
                        this.text.Append("\nNo AstarPath Object In The Scene");
                    }
                    else
                    {
                        if (ListPool<Vector3>.GetSize() > this.maxVecPool)
                        {
                            this.maxVecPool = ListPool<Vector3>.GetSize();
                        }
                        if (ListPool<GraphNode>.GetSize() > this.maxNodePool)
                        {
                            this.maxNodePool = ListPool<GraphNode>.GetSize();
                        }
                        this.text.Append("\nPool Sizes (size/total created)");
                        for (int j = 0; j < this.debugTypes.Length; j++)
                        {
                            this.debugTypes[j].Print(this.text);
                        }
                    }
                }
                this.cachedText = this.text.ToString();
            }
            if (this.font != null)
            {
                this.style.font = this.font;
                this.style.fontSize = this.fontSize;
            }
            this.boxRect.height = this.style.CalcHeight(new GUIContent(this.cachedText), this.boxRect.width);
            GUI.Box(this.boxRect, string.Empty);
            GUI.Label(this.boxRect, this.cachedText, this.style);
            if (this.showGraph)
            {
                float b = float.PositiveInfinity;
                float num5 = 0f;
                float num6 = float.PositiveInfinity;
                float num7 = 0f;
                for (int k = 0; k < this.graph.Length; k++)
                {
                    b = Mathf.Min(this.graph[k].memory, b);
                    num5 = Mathf.Max(this.graph[k].memory, num5);
                    num6 = Mathf.Min(this.graph[k].fps, num6);
                    num7 = Mathf.Max(this.graph[k].fps, num7);
                }
                GUI.color = Color.blue;
                float num9 = Mathf.RoundToInt(num5 / 100000f);
                GUI.Label(new Rect(5f, (Screen.height - AstarMath.MapTo(b, num5, 0f + this.graphOffset, this.graphHeight + this.graphOffset, (num9 * 1000f) * 100f)) - 10f, 100f, 20f), (num9 / 10f).ToString("0.0 MB"));
                num9 = Mathf.Round(b / 100000f);
                GUI.Label(new Rect(5f, (Screen.height - AstarMath.MapTo(b, num5, 0f + this.graphOffset, this.graphHeight + this.graphOffset, (num9 * 1000f) * 100f)) - 10f, 100f, 20f), (num9 / 10f).ToString("0.0 MB"));
                GUI.color = Color.green;
                num9 = Mathf.Round(num7);
                GUI.Label(new Rect(55f, (Screen.height - AstarMath.MapTo(num6, num7, 0f + this.graphOffset, this.graphHeight + this.graphOffset, num9)) - 10f, 100f, 20f), num9.ToString("0 FPS"));
                num9 = Mathf.Round(num6);
                GUI.Label(new Rect(55f, (Screen.height - AstarMath.MapTo(num6, num7, 0f + this.graphOffset, this.graphHeight + this.graphOffset, num9)) - 10f, 100f, 20f), num9.ToString("0 FPS"));
            }
        }
    }

    public void Start()
    {
        base.useGUILayout = false;
        this.fpsDrops = new float[this.fpsDropCounterSize];
        if (base.camera != null)
        {
            this.cam = base.camera;
        }
        else
        {
            this.cam = Camera.main;
        }
        this.graph = new GraphPoint[this.graphBufferSize];
        for (int i = 0; i < this.fpsDrops.Length; i++)
        {
            this.fpsDrops[i] = 1f / Time.deltaTime;
        }
    }

    public void Update()
    {
        if (this.show && (Application.isPlaying || this.showInEditor))
        {
            int num = GC.CollectionCount(0);
            if (this.lastCollectNum != num)
            {
                this.lastCollectNum = num;
                this.delta = Time.realtimeSinceStartup - this.lastCollect;
                this.lastCollect = Time.realtimeSinceStartup;
                this.lastDeltaTime = Time.deltaTime;
                this.collectAlloc = this.allocMem;
            }
            this.allocMem = (int) GC.GetTotalMemory(false);
            bool flag = this.allocMem < this.peakAlloc;
            this.peakAlloc = flag ? this.peakAlloc : this.allocMem;
            if (((Time.realtimeSinceStartup - this.lastAllocSet) > 0.3f) || !Application.isPlaying)
            {
                int num2 = this.allocMem - this.lastAllocMemory;
                this.lastAllocMemory = this.allocMem;
                this.lastAllocSet = Time.realtimeSinceStartup;
                this.delayedDeltaTime = Time.deltaTime;
                if (num2 >= 0)
                {
                    this.allocRate = num2;
                }
            }
            if (Application.isPlaying)
            {
                this.fpsDrops[Time.frameCount % this.fpsDrops.Length] = (Time.deltaTime == 0f) ? float.PositiveInfinity : (1f / Time.deltaTime);
                int index = Time.frameCount % this.graph.Length;
                this.graph[index].fps = (Time.deltaTime >= float.Epsilon) ? (1f / Time.deltaTime) : 0f;
                this.graph[index].collectEvent = flag;
                this.graph[index].memory = this.allocMem;
            }
            if ((Application.isPlaying && (this.cam != null)) && this.showGraph)
            {
                this.graphWidth = this.cam.pixelWidth * 0.8f;
                float positiveInfinity = float.PositiveInfinity;
                float b = 0f;
                float num6 = float.PositiveInfinity;
                float num7 = 0f;
                for (int i = 0; i < this.graph.Length; i++)
                {
                    positiveInfinity = Mathf.Min(this.graph[i].memory, positiveInfinity);
                    b = Mathf.Max(this.graph[i].memory, b);
                    num6 = Mathf.Min(this.graph[i].fps, num6);
                    num7 = Mathf.Max(this.graph[i].fps, num7);
                }
                int num9 = Time.frameCount % this.graph.Length;
                Matrix4x4 m = Matrix4x4.TRS(new Vector3((this.cam.pixelWidth - this.graphWidth) / 2f, this.graphOffset, 1f), Quaternion.identity, new Vector3(this.graphWidth, this.graphHeight, 1f));
                for (int j = 0; j < (this.graph.Length - 1); j++)
                {
                    if (j != num9)
                    {
                        this.DrawGraphLine(j, m, ((float) j) / ((float) this.graph.Length), ((float) (j + 1)) / ((float) this.graph.Length), AstarMath.MapTo(positiveInfinity, b, this.graph[j].memory), AstarMath.MapTo(positiveInfinity, b, this.graph[j + 1].memory), Color.blue);
                        this.DrawGraphLine(j, m, ((float) j) / ((float) this.graph.Length), ((float) (j + 1)) / ((float) this.graph.Length), AstarMath.MapTo(num6, num7, this.graph[j].fps), AstarMath.MapTo(num6, num7, this.graph[j + 1].fps), Color.green);
                    }
                }
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct GraphPoint
    {
        public float fps;
        public float memory;
        public bool collectEvent;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct PathTypeDebug
    {
        private string name;
        private Func<int> getSize;
        private Func<int> getTotalCreated;
        public PathTypeDebug(string name, Func<int> getSize, Func<int> getTotalCreated)
        {
            this.name = name;
            this.getSize = getSize;
            this.getTotalCreated = getTotalCreated;
        }

        public void Print(StringBuilder text)
        {
            int num = this.getTotalCreated();
            if (num > 0)
            {
                text.Append("\n").Append(("  " + this.name).PadRight(0x19)).Append(this.getSize()).Append("/").Append(num);
            }
        }
    }
}

